/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * Projects
 * Copyright (C) Arnaud Duval 2010 <arnaud.duval@gmail.com>
 * 
 * Projects is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Projects is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <RichTrackPoint.hpp>
#include <filesystem-utils.hpp>


///@brief Default constructor
RichTrackPoint::RichTrackPoint()
{
    latitude = 0.;
    longitude = 0.;
    altitude = 0.;
    distance = 0.;
    heartRate = 0;
    cadence = 0;
    speed = 0.;
    power = 0.;
    intervaleIndex = 0;
}
       
///@brief Copy constructor
///@param p RichTrackPointObject to copy
RichTrackPoint::RichTrackPoint(const RichTrackPoint& p)
{
    time = p.time;
    latitude = p.latitude;
    longitude = p.longitude;
    altitude = p.altitude;
    distance = p.distance;
    heartRate = p.heartRate;
    cadence = p.cadence;
    speed = p.speed;
    power = p.power;
    intervaleIndex = p.intervaleIndex;
}

///brief Destructor
RichTrackPoint::~RichTrackPoint()
{

}

///@brief Overload of = operator
///@param p RichTrackPointObject to copy
RichTrackPoint& RichTrackPoint::operator= (const RichTrackPoint &p)
{
    time = p.time;
    latitude = p.latitude;
    longitude = p.longitude;
    altitude = p.altitude;
    distance = p.distance;
    heartRate = p.heartRate;
    cadence = p.cadence;
    speed = p.speed;
    power = p.power;
    intervaleIndex = p.intervaleIndex;
}

///@brief Read a rich track point from a XML node in a TCX file
///@param trackPointNode XML node to parse
void RichTrackPoint::ReadFromTcxFile(xmlpp::Node* trackPointNode)
{
    if(trackPointNode->get_name() == "Trackpoint")
    {
        //Parsing track node childen
        xmlpp::Node::NodeList trackPointNodeChildren = trackPointNode->get_children();
        for (xmlpp::Node::NodeList::iterator iterTrackPointNodeChildren = trackPointNodeChildren.begin();
             iterTrackPointNodeChildren != trackPointNodeChildren.end();
             ++iterTrackPointNodeChildren)
        {
            xmlpp::Node* trackPointNodeChild = dynamic_cast<xmlpp::Node*>(*iterTrackPointNodeChildren);
            if(trackPointNodeChild->get_name() == "Time")
            {
                ///@warning Time is given in UTC zone. For France, we should add +1 hour in winter and +2 hours in summer
                time.SetWithFormat(((xmlpp::TextNode*)(*((trackPointNodeChild->get_children()).begin())))->get_content(), "yyyy-mm-ddThh:nn:ss.000Z");
            }
            else if(trackPointNodeChild->get_name() == "Position")
            {
                //Parsing node children
                xmlpp::Node::NodeList posNodeChildren = trackPointNodeChild->get_children();
                for (xmlpp::Node::NodeList::iterator iterPosNodeChildren = posNodeChildren.begin();
                     iterPosNodeChildren != posNodeChildren.end();
                     ++iterPosNodeChildren)
                {
                    xmlpp::Node* posNodeChild = dynamic_cast<xmlpp::Node*>(*iterPosNodeChildren);
                    if(posNodeChild->get_name() == "LatitudeDegrees")
                        latitude = StringToDouble(((xmlpp::TextNode*)(*((posNodeChild->get_children()).begin())))->get_content());
                    else if(posNodeChild->get_name() == "LongitudeDegrees")
                        longitude = StringToDouble(((xmlpp::TextNode*)(*((posNodeChild->get_children()).begin())))->get_content());
                }
            }
            else if(trackPointNodeChild->get_name() == "AltitudeMeters")
            {
                altitude = StringToDouble(((xmlpp::TextNode*)(*((trackPointNodeChild->get_children()).begin())))->get_content());
            }
            else if(trackPointNodeChild->get_name() == "DistanceMeters")
            {
                distance = StringToDouble(((xmlpp::TextNode*)(*((trackPointNodeChild->get_children()).begin())))->get_content());
                distance /= 1000.;
            }
            else if(trackPointNodeChild->get_name() == "HeartRateBpm")
            {
                // Parsing node children
                xmlpp::Node::NodeList bpmNodeChildren = trackPointNodeChild->get_children();
                for(xmlpp::Node::NodeList::iterator iterBpmNodeChildren = bpmNodeChildren.begin();
                    iterBpmNodeChildren != bpmNodeChildren.end();
                    ++iterBpmNodeChildren)
                {
                    xmlpp::Node* bpmNodeChild = dynamic_cast<xmlpp::Node*>(*iterBpmNodeChildren);
                    if(bpmNodeChild->get_name() == "Value")
                        heartRate = StringToUInt(((xmlpp::TextNode*)(*((bpmNodeChild->get_children()).begin())))->get_content());
                }
            }
            else if(trackPointNodeChild->get_name() == "Cadence")
                cadence = StringToUInt(((xmlpp::TextNode*)(*((trackPointNodeChild->get_children()).begin())))->get_content());
            else if(trackPointNodeChild->get_name() == "Extensions")
            {
                // Parsing node children
                xmlpp::Node::NodeList extensionsNodeChildren = trackPointNodeChild->get_children();
                for(xmlpp::Node::NodeList::iterator iterExtensionsNodeChildren = extensionsNodeChildren.begin();
                    iterExtensionsNodeChildren != extensionsNodeChildren.end();
                    ++iterExtensionsNodeChildren)
                {
                    xmlpp::Node* extensionsChild = dynamic_cast<xmlpp::Node*> (*iterExtensionsNodeChildren);
                    if(extensionsChild->get_name() == "TPX")
                    {
                        // Parsing node children
                        xmlpp::Node::NodeList ns3NodeChildren = extensionsChild->get_children();
                        for (xmlpp::Node::NodeList::iterator iterNs3NodeChildren = ns3NodeChildren.begin();
                             iterNs3NodeChildren != ns3NodeChildren.end();
                             ++iterNs3NodeChildren)
                        {
                            xmlpp::Node* ns3Child = dynamic_cast<xmlpp::Node*>(*iterNs3NodeChildren);
                            if(ns3Child->get_name() == "Speed")
                                speed = StringToDouble(((xmlpp::TextNode*)(*((ns3Child->get_children()).begin())))->get_content());
                            if(ns3Child->get_name() == "Watts")
                                power = StringToDouble(((xmlpp::TextNode*)(*((ns3Child->get_children()).begin())))->get_content());
                        }
                    }
                }
            }
        }
    }
}

///@brief Write to native XML format
///@param fout Reference to output file stream to write
void RichTrackPoint::WriteXML(std::ofstream& fout)
{
    fout << "      <Time>" <<  time << "</Time>\n";
    fout << "      <Latitude>" << latitude << "</Latitude>\n";
    fout << "      <Longitude>" << longitude << "</Longitude>\n";
    fout << "      <Altitude>" << altitude << "</Altitude>\n";
    fout << "      <Distance>" << distance << "</Distance>\n";
    fout << "      <HeartRate>" << heartRate << "</HeartRate>\n";
    fout << "      <Cadence>" << cadence << "</Cadence>\n";
    fout << "      <Speed>" << speed << "</Speed>\n";
    fout << "      <Power>" << power << "</Power>\n";    
    fout << "      <IntervaleIndex>" << intervaleIndex << "</IntervaleIndex>\n";
}

///@brief return the date and time
DateTime RichTrackPoint::GetDateTime()
{
    return time;
}

///@brief Return the power
double RichTrackPoint::GetPower()
{
    return power;
}

///@brief Read from a file containing the history
///@param node Pointer to XML node to read
void RichTrackPoint::ReadHistoryFile(xmlpp::Node* node)
{
    if(node->get_name() == "TrackPoint")
    {
        xmlpp::Node::NodeList pointNodeChildren = node->get_children();
        for(xmlpp::Node::NodeList::iterator iterPointNodeChildren = pointNodeChildren.begin();
            iterPointNodeChildren != pointNodeChildren.end() ;
            ++iterPointNodeChildren)
        {
            xmlpp::Node* pointNodeChild = dynamic_cast<xmlpp::Node*>(*iterPointNodeChildren);
            if(pointNodeChild->get_name() == "Time")
                time.SetWithFormat(((xmlpp::TextNode*)(*((pointNodeChild->get_children()).begin())))->get_content(), "yyyy-mm-dd--hh:nn:ss");
            else if(pointNodeChild->get_name() == "Latitude")
                latitude = StringToDouble(((xmlpp::TextNode*)(*((pointNodeChild->get_children()).begin())))->get_content());
            else if(pointNodeChild->get_name() == "Longitude")
                longitude = StringToDouble(((xmlpp::TextNode*)(*((pointNodeChild->get_children()).begin())))->get_content());
            else if(pointNodeChild->get_name() == "Altitude")
                altitude = StringToDouble(((xmlpp::TextNode*)(*((pointNodeChild->get_children()).begin())))->get_content());
            else if(pointNodeChild->get_name() == "Distance")
                distance = StringToDouble(((xmlpp::TextNode*)(*((pointNodeChild->get_children()).begin())))->get_content());
            else if(pointNodeChild->get_name() == "HeartRate")
                heartRate = StringToUInt(((xmlpp::TextNode*)(*((pointNodeChild->get_children()).begin())))->get_content());
            else if(pointNodeChild->get_name() == "Cadence")
                cadence = StringToUInt(((xmlpp::TextNode*)(*((pointNodeChild->get_children()).begin())))->get_content());
            else if(pointNodeChild->get_name() == "Speed")
                speed = StringToDouble(((xmlpp::TextNode*)(*((pointNodeChild->get_children()).begin())))->get_content());
            else if(pointNodeChild->get_name() == "Power")
                power = StringToDouble(((xmlpp::TextNode*)(*((pointNodeChild->get_children()).begin())))->get_content());
            else if(pointNodeChild->get_name() == "IntervaleIndex")
                intervaleIndex = StringToUInt(((xmlpp::TextNode*)(*((pointNodeChild->get_children()).begin())))->get_content());
        }
    }
}

///@brief Overload of < operator to sort rich track points depending on their date
///@param p1 left hand operand
///@param p2 right hand operand
bool operator < (const RichTrackPoint& p1 , const RichTrackPoint &p2)
{
    return (p1.time < p2.time);
}
